#pragma once
#include "LockGuard.hpp"

#include "Thread.hpp"
#include <queue>
#include <vector>
#include <mutex>
const int gnum = 10;
template <class T>
class ThreadPool;

template <class T>
class ThreadData
{
public:
    ThreadPool<T> *threadpool;
    std::string name;

public:
    ThreadData(ThreadPool<T> *tp, const std::string &n) : threadpool(tp), name(n)
    {
    }
};

using namespace ThreadNs;
template <class T>
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadData<T> *td = (ThreadData<T> *)args;
        while (true)
        {
            T t;
            {
                LockGuard lockguard(td->threadpool->Mutex());
                while (td->threadpool->isQueueEmpty())
                {
                    td->threadpool->threadWait();
                }
                // 有任务
                t = td->threadpool->pop();
            }
            cout << td->name << "获取了一个任务：" << t.toTaskString() << endl;
            cout << "并处理完成，结果是: " << t() << endl;
        }
        delete td;
        return nullptr;
    }

    void operator=(const ThreadPool &) = delete;
    ThreadPool(const ThreadPool &) = delete;

public:
    void lockQueue() { pthread_mutex_lock(&_mutex); }
    void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    bool isQueueEmpty() { return _taskqueue.empty(); }
    void threadWait() { pthread_cond_wait(&_cond, &_mutex); }
    pthread_mutex_t * Mutex()
    {
        return &_mutex;
    }
    ThreadPool(const int &num = gnum)
        : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; ++i)
        {
            _threads.push_back(new Thread());
        }
    }
    void run()
    {
        for (auto &t : _threads)
        {
            ThreadData<T> *td = new ThreadData<T>(this, t->threadname());
            t->start(handlerTask, td);
            cout << t->threadname() << " start ..." << endl;
        }
    }
    void push(const T &in)
    {
        LockGuard lockguard(&_mutex);
        _taskqueue.push(in);
        pthread_cond_signal(&_cond);
    }
    T pop()
    {
        T t = _taskqueue.front();
        _taskqueue.pop();
        return t;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (const auto &t : _threads)
            delete t;
    }
    // static ThreadPool<T> *getInstance()
    // {
    //     if (nullptr == tp)
    //     {
    //         _singlock.lock();
    //         if (nullptr == tp)
    //         {
    //             tp = new ThreadPool<T>();
    //         }
    //         _singlock.unlock();
    //     }
    //     return tp;
    // }
public:
    static ThreadPool<T> *getInstance()
    {
        single_lock.lock();
        if (tp == NULL)
            tp = new ThreadPool<T>();
        single_lock.unlock();
        return tp;
    }

private:
    int _num;
    vector<Thread *> _threads;
    queue<T> _taskqueue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool<T> *tp;
    static mutex single_lock;

};
template <class T>
ThreadPool<T> *ThreadPool<T>::tp = nullptr;

template <class T>
mutex ThreadPool<T>::single_lock;